package com.ccc.boot.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ccc.boot.base.BaseServiceImpl;
import com.ccc.boot.constant.CommonConstant;
import com.ccc.boot.constant.DictConstant;
import com.ccc.boot.exception.BusinessException;
import com.ccc.boot.pojo.Query;
import com.ccc.boot.redis.constant.RedisConstant;
import com.ccc.boot.redis.util.RedisUtils;
import com.ccc.boot.response.ResponseCode;
import com.ccc.boot.system.entity.SysApi;
import com.ccc.boot.system.mapper.SysApiMapper;
import com.ccc.boot.system.pojo.AuthApiVO;
import com.ccc.boot.system.service.RelRoleResourceService;
import com.ccc.boot.system.service.SysApiService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 按钮接口资源表 业务处理实现类
 *
 * @author superC
 * @version 0.1.0
 * @date 2022-03-30
 */
@Service
public class SysApiServiceImpl extends BaseServiceImpl<SysApiMapper, SysApi> implements SysApiService {

    @Autowired
    private RelRoleResourceService relRoleResourceService;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        try {
            if (checkId(id)) {
                // 删除
                boolean result = super.removeById(id);
                // 删除中间表
                if (result) {
                    boolean resultRel = relRoleResourceService.delete(DictConstant.RESOURCE_TYPE_API, id);

                    // 清除缓存
                    if (resultRel) {
                        resetCache2Apis();
                    }

                    return resultRel;
                }
                return false;
            } else {
                throw new BusinessException(ResponseCode.RESULT_DATA_NONE);
            }
        } catch (Exception e) {
            logger.error("【捕获异常-删除操作】\r\n异常记录：", e);
            //手工回滚异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException(ResponseCode.DATA_DELETE_FAILURE);
        }
    }

    @Override
    public boolean update(SysApi entity) {
        try {
            if (checkId(entity.getId())) {
                boolean isAuth = relRoleResourceService.check(DictConstant.RESOURCE_TYPE_API, entity.getId());
                if (isAuth) {
                    // 清除缓存
                    resetCache2Apis();
                }

                return super.updateById(entity);
            } else {
                throw new BusinessException(ResponseCode.DATA_UPDATE_FAILURE);
            }
        } catch (Exception e) {
            logger.error("【捕获异常-编辑操作】\r\n异常记录：", e);
            //手工回滚异常
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            throw new BusinessException(e.getMessage());
        }
    }

    @Override
    public IPage<SysApi> page(Query query) {
        Page<SysApi> page = new Page<>(query.getCurrent(), query.getSize());
        QueryWrapper<SysApi> wrapper = new QueryWrapper<>();
        // 全局进行模糊查询
        query.forEach((column, value) -> {
            // 非空，进行模糊查询
            if (value != null && value != "") {
                if (StringUtils.equals("menu_id", column)) {
                    wrapper.eq(column, value);
                } else {
                    wrapper.like(column, value);
                }
            }
        });
        return super.page(page, wrapper);
    }

    @Override
    public boolean deleteByMenuId(Long menuId) {
        LambdaQueryWrapper<SysApi> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysApi::getMenuId, menuId);
        return baseMapper.delete(wrapper) > 0;
    }

    @Override
    public List<SysApi> getAllApis(Long menuId) {
        if (menuId == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<SysApi> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysApi::getMenuId, menuId);
        wrapper.orderByAsc(SysApi::getOrderNum);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<SysApi> getEnabledApis(Long menuId) {
        if (menuId == null) {
            return new ArrayList<>();
        }
        LambdaQueryWrapper<SysApi> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysApi::getStatus, DictConstant.STATUS_ENABLE);
        wrapper.eq(SysApi::getMenuId, menuId);
        wrapper.orderByAsc(SysApi::getOrderNum);
        return baseMapper.selectList(wrapper);
    }

    @Override
    public List<Long> getEnabledApiIds(Long menuId) {
        List<SysApi> apiList = getEnabledApis(menuId);
        if (apiList.isEmpty()) {
            return null;
        }
        return apiList.stream().map(SysApi::getId).collect(Collectors.toList());
    }

    @Override
    @Cacheable(value = RedisConstant.AUTH_ROLES_APIS, key = "#rolesStr", unless = "#result.size() == 0")
    public List<SysApi> getApisByRoles(String rolesStr) {
        String[] roleArr = rolesStr.split(CommonConstant.SEPARATOR_COMMA);
//        Set<String> roles = Arrays.stream(roleArr).collect(Collectors.toSet());
        return baseMapper.getApisByRoles(DictConstant.STATUS_ENABLE, DictConstant.RESOURCE_TYPE_API, roleArr);
    }

    @Override
    public List<AuthApiVO> getAuthApiList(Long roleId, Long menuId) {
        List<AuthApiVO> list = new ArrayList<>();
        List<SysApi> apiList = getEnabledApis(menuId);
        apiList.forEach(sysApi -> {
            AuthApiVO vo = new AuthApiVO();
            BeanUtils.copyProperties(sysApi, vo);
            // 判断当前按钮资源是否已授权给所传角色
            vo.setAuthorized(relRoleResourceService.check(roleId, DictConstant.RESOURCE_TYPE_API, sysApi.getId()));
            list.add(vo);
        });
        return list;
    }

    /**
     * 清除按钮资源相关的redis缓存数据
     *
     * @return {@link boolean}
     * @date 2022/5/3 20:08
     * @author superC
     */
    @Override
    public void resetCache2Apis() {
        // 清除按钮资源权限
        String authApisKey = RedisConstant.AUTH_ROLES_APIS;
        redisUtils.delByPrefix(authApisKey);
    }
}
